import { useEffect } from "react";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import * as CANNON from "cannon-es";

import { CannonEsDebuggerPro } from "@vladkrutenyuk/cannon-es-debugger-pro";
function App() {
    useEffect(() => {
        // 创建世界
        const scene = new THREE.Scene();
        // 创建相机
        const camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        // 设置相机位置
        camera.position.z = 20;
        camera.position.x = 0;
        camera.position.y = 10;
        camera.lookAt(0, 20, 0); // 设置相机朝向

        const root = new THREE.Group();
        scene.add(root); // 将根节点添加到场景中

        // 创建两个数组更新物理世界和threejs世界
        const cannonBodies = [];
        const threeObjects = [];

        // 创建物理世界
        const world = new CANNON.World();
        // 设置重力
        world.gravity.set(0, -9.82, 0); // m/s²

        const color = 0xe60c0c; // or 'rgb(228, 14, 88)', '#e60c0c', 'red'
        const offset = 0.009;
        const cannonDebugger = new CannonEsDebuggerPro(root, world, color, offset);


        // 添加地面
        {
            {
                // 创建物理世界平面
                const planeShape = new CANNON.Plane();
                const planeBody = new CANNON.Body({
                    mass: 0, // 质量为0表示静止物体
                    position: new CANNON.Vec3(0, 0, 0), // 初始位置
                });
                // 设置平面的旋转
                planeBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); // 绕x轴旋转90度
                planeBody.addShape(planeShape);
                world.addBody(planeBody);
            }
            {
                // 创建three平面
                const planeShape = new THREE.BoxGeometry(100, 0.1, 100);
                const planeMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff });
                const plane = new THREE.Mesh(planeShape, planeMaterial);
                // 设置平面位置
                plane.position.y = -0.1;
                // 将平面添加到场景中
                scene.add(plane);
            }
        }


        // 添加车辆
        {
            {
                // 创建物理世界车辆
                const vehicleShape = new CANNON.Box(new CANNON.Vec3(4, 0.5, 5)); // 车身
                const vehicleBody = new CANNON.Body({
                    mass: 3, // 质量
                    position: new CANNON.Vec3(0, 3, 0), // 初始位置
                });
                vehicleBody.addShape(vehicleShape);
                world.addBody(vehicleBody);
                cannonBodies.push(vehicleBody); // 将物理世界车辆添加到数组中

                // 创建刚性车子
                const vehicle = new CANNON.RigidVehicle({
                    chassisBody: vehicleBody, // 车身
                })

                // 创建轮子1
                const wheelBody1 = new CANNON.Body({
                    mass: 1, // 质量
                    shape: new CANNON.Sphere(1.5), // 车轮
                })
                cannonBodies.push(wheelBody1); // 将物理世界车轮添加到数组中
                vehicle.addWheel({
                    body: wheelBody1, // 车轮
                    position: new CANNON.Vec3(-5.5, -1, -4), // 初始位置
                    axis: new CANNON.Vec3(1, 0, 0), // 车轮旋转轴
                    direction: new CANNON.Vec3(0, 0, 1), // 车轮方向
                })
                // 创建轮子2
                const wheelBody2 = new CANNON.Body({
                    mass: 1, // 质量
                    shape: new CANNON.Sphere(1.5), // 车轮
                })
                cannonBodies.push(wheelBody2); // 将物理世界车轮添加到数组中
                vehicle.addWheel({
                    body: wheelBody2, // 车轮
                    position: new CANNON.Vec3(5.5, -1, -4), // 初始位置
                    axis: new CANNON.Vec3(1, 0, 0), // 车轮旋转轴
                    direction: new CANNON.Vec3(0, 0, 1), // 车轮方向
                })
                // 创建轮子3
                const wheelBody3 = new CANNON.Body({
                    mass: 1, // 质量
                    shape: new CANNON.Sphere(1.5), // 车轮
                })
                cannonBodies.push(wheelBody3); // 将物理世界车轮添加到数组中
                vehicle.addWheel({
                    body: wheelBody3, // 车轮
                    position: new CANNON.Vec3(-5.5, -1, 4), // 初始位置
                    axis: new CANNON.Vec3(1, 0, 0), // 车轮旋转轴
                    direction: new CANNON.Vec3(0, 0, 1), // 车轮方向
                })
                // 创建轮子4
                const wheelBody4 = new CANNON.Body({
                    mass: 1, // 质量
                    shape: new CANNON.Sphere(1.5), // 车轮
                })
                cannonBodies.push(wheelBody4); // 将物理世界车轮添加到数组中
                vehicle.addWheel({
                    body: wheelBody4, // 车轮
                    position: new CANNON.Vec3(5.5, -1, 4), // 初始位置
                    axis: new CANNON.Vec3(1, 0, 0), // 车轮旋转轴
                    direction: new CANNON.Vec3(0, 0, 1), // 车轮方向
                })


                vehicle.addToWorld(world); // 将车辆添加到物理世界中


                // 键盘控制车辆
                window.addEventListener("keydown", (event) => {
                    console.log(event.key)
                    switch (event.key) {
                        case "w":
                            vehicle.setWheelForce(-100, 0); // 前进
                            vehicle.setWheelForce(-100, 1); // 前进
                            break;
                        case "s":
                            vehicle.setWheelForce(100, 0); // 前进
                            vehicle.setWheelForce(100, 1); // 前进
                            break;
                        case "a":
                            vehicle.setSteeringValue(Math.PI/4, 0); // 左转
                            vehicle.setSteeringValue(Math.PI/4, 1); // 左转
                            break;
                        case "d":
                            vehicle.setSteeringValue(-Math.PI/4, 0); // 左转
                            vehicle.setSteeringValue(-Math.PI/4, 1); // 左转
                            break;
                        case " ": // 刹车
                            vehicle.setWheelForce(0, 2); // 停止前进
                            vehicle.setWheelForce(0, 3); // 停止前进
                            
                        default:
                            break;
                    }
                });
                window.addEventListener("keyup", (event) => {
                    switch (event.key) {
                        case "w":
                            vehicle.setWheelForce(0, 0); // 停止前进
                            vehicle.setWheelForce(0, 1); // 前进
                            break;
                        case "s":
                            vehicle.setWheelForce(0, 0); // 停止前进
                            vehicle.setWheelForce(0, 1); // 前进
                            break;
                        case "a":
                            vehicle.setSteeringValue(0, 0); // 停止左转
                            vehicle.setSteeringValue(0, 1); // 停止左转
                            break;
                        case "d":
                            vehicle.setSteeringValue(0, 0); // 停止
                            vehicle.setSteeringValue(0, 1); // 停止
                            break;
                        default:
                            break;
                    }
                });
            }
            {
                // 创建three车辆
                const vehicleShape = new THREE.BoxGeometry(8, 1, 10); // 车身
                const vehicleMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
                const vehicle = new THREE.Mesh(vehicleShape, vehicleMaterial);
                // 设置车辆位置
                vehicle.position.y = 0.5;
                // 将车辆添加到场景中
                scene.add(vehicle);
                threeObjects.push(vehicle); // 将three车辆添加到数组中

                // 创建车轮
                const wheelShape = new THREE.SphereGeometry(1.5, 16, 16); // 车轮
                const wheelMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });
                const wheel1 = new THREE.Mesh(wheelShape, wheelMaterial); // 车轮1
                const wheel2 = new THREE.Mesh(wheelShape, wheelMaterial); // 车轮2
                const wheel3 = new THREE.Mesh(wheelShape, wheelMaterial); // 车轮2
                const wheel4 = new THREE.Mesh(wheelShape, wheelMaterial); // 车轮2

                root.add(wheel1); // 将车轮添加到根节点中
                threeObjects.push(wheel1); // 将three车轮添加到数组中
                root.add(wheel2); // 将车轮添加到根节点中
                threeObjects.push(wheel2); // 将three车轮添加到数组中
                root.add(wheel3); // 将车轮添加到根节点中
                threeObjects.push(wheel3); // 将three车轮添加到数组中
                root.add(wheel4); // 将车轮添加到根节点中
                threeObjects.push(wheel4); // 将three车轮添加到数组中
            }

        }




        // 创建渲染器
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 将渲染器添加到DOM中
        document.getElementById("app").appendChild(renderer.domElement);

        // 添加轨道控制器
        const controls = new OrbitControls(camera, renderer.domElement);
        // 创建坐标辅助器
        const axesHelper = new THREE.AxesHelper(5);
        scene.add(axesHelper); // 将坐标辅助器添加到场景中

        // 创建动画函数
        const animate = function () {
            // 更新物理世界
            world.step(1 / 60); // 60fps
            // 更新threejs世界
            for (let i = 0; i < cannonBodies.length; i++) {
                const body = cannonBodies[i];
                const mesh = threeObjects[i];
                // 更新threejs物体的位置和旋转
                mesh.position.copy(body.position);
                mesh.quaternion.copy(body.quaternion);
            }
            cannonDebugger.update(); // 更新调试器

            // 更新轨道控制器
            controls.update();

            requestAnimationFrame(animate);

            // 渲染场景
            renderer.render(scene, camera);
        };
        // 调用动画函数
        animate();

        return () => {
            // 清除渲染器
            renderer.dispose();
            // 清除场景
            scene.clear();
            // 清除相机
            camera.clear();
            // 清除渲染器DOM
            const app = document.getElementById("app");
            if (app) {
                app.removeChild(renderer.domElement);
            }
        };
    }, []);
    return <div id="app"></div>;
}

export default App;
